<h1><code ng:non-bindable=""></code>
    <span class="hint"></span>
</h1>
<div><a href="http://github.com/angular/angular.js/edit/master/docs/content/cookbook/mvc.ngdoc"
        class="improve-docs btn btn-primary">Improve this doc</a>

    <div class="cookbook-page cookbook-mvc-page"><p>MVC allows for a clean and testable separation between the behavior
        (controller) and the view
        (HTML template). A Controller is just a JavaScript class which is grafted onto the scope of the
        view. This makes it very easy for the controller and the view to share the model.</p>

        <p>The model is a set of objects and primitives that are referenced from the Scope ($scope) object.
            This makes it very easy to test the controller in isolation since one can simply instantiate the
            controller and test without a view, because there is no connection between the controller and the
            view.</p>

        <h3>Source</h3>

        <div source-edit="" source-edit-deps="angular.js script.js" source-edit-html="index.html-13" source-edit-css=""
             source-edit-js="script.js-12" source-edit-unit="" source-edit-scenario="scenario.js-14"></div>
        <div class="tabbable">
            <div class="tab-pane" title="index.html">
                <pre class="prettyprint linenums" ng-set-text="index.html-13"
                     ng-html-wrap=" angular.js script.js"></pre>
                <script type="text/ng-template" id="index.html-13">


                    <h4>Tic-Tac-Toe</h4>
                    <div ng-controller="TicTacToeCntl">
                        Next Player: {{nextMove}}
                        <div class="winner" ng-show="winner">Player {{winner}} has won!</div>
                        <table class="board">
                            <tr ng-repeat="row in board" style="height:15px;">
                                <td ng-repeat="cell in row" ng-style="cellStyle"
                                    ng-click="dropPiece($parent.$index, $index)">{{cell}}
                                </td>
                            </tr>
                        </table>
                        <button ng-click="reset()">reset board</button>
                    </div>
                </script>
            </div>
            <div class="tab-pane" title="script.js">
                <pre class="prettyprint linenums" ng-set-text="script.js-12"></pre>
                <script type="text/ng-template" id="script.js-12">
                    function TicTacToeCntl($scope, $location) {
                    $scope.cellStyle= {
                    'height': '20px',
                    'width': '20px',
                    'border': '1px solid black',
                    'text-align': 'center',
                    'vertical-align': 'middle',
                    'cursor': 'pointer'
                    };

                    $scope.reset = function() {
                    $scope.board = [
                    ['', '', ''],
                    ['', '', ''],
                    ['', '', '']
                    ];
                    $scope.nextMove = 'X';
                    $scope.winner = '';
                    setUrl();
                    };

                    $scope.dropPiece = function(row, col) {
                    if (!$scope.winner && !$scope.board[row][col]) {
                    $scope.board[row][col] = $scope.nextMove;
                    $scope.nextMove = $scope.nextMove == 'X' ? 'O' : 'X';
                    setUrl();
                    }
                    };

                    $scope.reset();
                    $scope.$watch(function() { return $location.search().board;}, readUrl);

                    function setUrl() {
                    var rows = [];
                    angular.forEach($scope.board, function(row) {
                    rows.push(row.join(','));
                    });
                    $location.search({board: rows.join(';') + '/' + $scope.nextMove});
                    }

                    function grade() {
                    var b = $scope.board;
                    $scope.winner =
                    row(0) || row(1) || row(2) ||
                    col(0) || col(1) || col(2) ||
                    diagonal(-1) || diagonal(1);
                    function row(row) { return same(b[row][0], b[row][1], b[row][2]);}
                    function col(col) { return same(b[0][col], b[1][col], b[2][col]);}
                    function diagonal(i) { return same(b[0][1-i], b[1][1], b[2][1+i]);}
                    function same(a, b, c) { return (a==b && b==c) ? a : '';};
                    }

                    function readUrl(value) {
                    if (value) {
                    value = value.split('/');
                    $scope.nextMove = value[1];
                    angular.forEach(value[0].split(';'), function(row, col){
                    $scope.board[col] = row.split(',');
                    });
                    grade();
                    }
                    }
                    }
                </script>
            </div>
            <div class="tab-pane" title="End to end test">
                <pre class="prettyprint linenums" ng-set-text="scenario.js-14"></pre>
                <script type="text/ng-template" id="scenario.js-14">
                    it('should play a game', function() {
                    piece(1, 1);
                    expect(binding('nextMove')).toEqual('O');
                    piece(3, 1);
                    expect(binding('nextMove')).toEqual('X');
                    piece(1, 2);
                    piece(3, 2);
                    piece(1, 3);
                    expect(element('.winner').text()).toEqual('Player X has won!');
                    });

                    function piece(row, col) {
                    element('.board tr:nth-child('+row+') td:nth-child('+col+')').click();
                    }
                </script>
            </div>
        </div>
        <h3>Demo</h3>

        <div class="well doc-example-live" ng-embed-app="" ng-set-html="index.html-13"
             ng-eval-javascript="script.js-12"></div>

        <h1 id="thingstonotice">Things to notice</h2>

            <ul>
                <li>The controller is defined in JavaScript and has no reference to the rendering logic.</li>
                <li>The controller is instantiated by Angular and injected into the view.</li>
                <li>The controller can be instantiated in isolation (without a view) and the code will still execute.
                    This makes it very testable.
                </li>
                <li>The HTML view is a projection of the model. In the above example, the model is stored in the
                    board variable.
                </li>
                <li>All of the controller's properties (such as board and nextMove) are available to the view.</li>
                <li>Changing the model changes the view.</li>
                <li>The view can call any controller function.</li>
                <li>In this example, the <code>setUrl()</code> and <code>readUrl()</code> functions copy the game state
                    to/from the URL's
                    hash so the browser's back button will undo game steps. See deep-linking. This example calls <a
                            href="api/ng.$rootScope.Scope#$watch"><code>$watch()</code></a> to set up a listener that
                    invokes <code>readUrl()</code> when needed.
                </li>
            </ul>
    </div>
</div>
